#pragma once

#include <iostream>
#include <memory>
#include <unordered_map>
#include "EPoller.hpp"
#include "Connection.hpp"
#include "Log.hpp"

using namespace std;

class Reactor
{
    static const int revs_num = 128;
    static const int timeout = -1;

private:
    bool IsConnectionExistsHelper(int sockfd)
    {
        auto it = _connections.find(sockfd);
        if (it == _connections.end())
            return false;
        else
            return true;
    }

    bool IsConnectionExists(const std::shared_ptr<Connection> &conn)
    {
        return IsConnectionExistsHelper(conn->GetFd());
    }

    bool IsConnectionExists(int sockfd)
    {
        return IsConnectionExistsHelper(sockfd);
    }

    bool IsConnectionEmpty() { return _connections.empty(); }

    // 等待一次
    int LoopOnce()
    {
        return _epoller->WaitEvent(_revs, revs_num, timeout);
    }

    // 事件派发
    void Dispatcher(int n)
    {
        for (int i = 0; i < n; i++)
        {
            int sockfd = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;
            // 1.所有异常处理, 统一转化成IO错误 2.所有的IO异常, 统一转化成一个异常处理函数
            if (revents & EPOLLERR) // 异常
                revents |= (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLHUP) // 链接关闭
                revents |= (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLIN) // 读事件就绪
            {
                // 不需要区分异常和时候是listensocket
                if (IsConnectionExists(sockfd))
                    _connections[sockfd]->Recver();
            }
            if (revents & EPOLLOUT) // 写事件就绪
            {
                if (IsConnectionExists(sockfd))
                    _connections[sockfd]->Sender();
            }
        }
    }

public:
    Reactor() : _epoller(std::make_unique<Epoller>()),
                  _isrunning(false)
    {
    }

    void Debug()
    {
        for(auto it : _connections)
        {
            std::cout << it.first << ":" << it.second->GetEvents() << std::endl;
        }
    }

    void Loop()
    {
        if(IsConnectionEmpty()) return;
        _isrunning = true;
        while (_isrunning)
        {
            // Debug();
            int n = LoopOnce();
            LOG(LogLevel::DEBUG) << "就绪事件个数: " << n; 
            Dispatcher(n);
            LOG(LogLevel::DEBUG) << "完成事件派发";
        }
        _isrunning = false;
    }

    void Stop()
    {
        _isrunning = false;
    }

    void DelConnection(int sockfd)
    {
        _epoller->DeleEvent(sockfd);
        _connections.erase(sockfd);
        close(sockfd);
        LOG(LogLevel::INFO) << "sockfd:" << sockfd << " quit";
    }

    void AddConnection(std::shared_ptr<Connection> &conn)
    {
        if (IsConnectionExists(conn))
        {
            LOG(LogLevel::WARNING) << "connection is exists" << conn->GetFd();
            return;
        }
        uint32_t events = conn->GetEvents();
        int sockfd = conn->GetFd();
        _epoller->AddEvent(sockfd, events);
        conn->SetOwner(this);

        _connections[sockfd] = conn;
    }

    void EnableReadWrite(int sockfd, bool enableread, bool enablewrite)
    {
        if(!IsConnectionExists(sockfd))
        {
            LOG(LogLevel::WARNING) << "(EnableReadWrite)sockfd is not exists: " << sockfd;
            return;
        }
        uint32_t new_events = (EPOLLET | (enableread ? EPOLLIN : 0) | (enablewrite ? EPOLLOUT : 0));
        _connections[sockfd]->SetEvent(new_events);
        _epoller->ModEvent(sockfd, new_events);
    }

    ~Reactor() {}

private:
    // 1.epoll模块
    std::unique_ptr<Epoller> _epoller;
    // // 2.listen模块
    // std::shared_ptr<Listener> _listener;
    // 3.connection模块
    std::unordered_map<int, std::shared_ptr<Connection>> _connections;

    // 是否启动
    bool _isrunning;
    // 就绪事件
    struct epoll_event _revs[revs_num];
};